/*
 * Copyrignt (c) xuzeshui.com. All Rights Reserved.
 * Author: Zeshui Xu<i@xuzeshui.com>
 * Created Time: 2015-09-29 20:27:29
 * Last Modified: 2016-09-09 10:59:58
 * File Name: user/user.go
 * Description:
 */
package user

import (
	"errors"
	"fmt"
	"strings"

	"passport/errorcode"
	"passport/models"

	"doubimeizhi.com/utility"

	log "github.com/cihub/seelog"
	"github.com/garyburd/redigo/redis"
	"github.com/jmoiron/jsonq"
)

var (
	userservice *UserService
)

/*
	UserInfo的基本信息结构
*/
type UserInfo struct {
	UserId         string `redis:"userid"`        //自动生成唯一标识
	Password       string `redis:"passwd"`        //登陆密码
	NickName       string `redis:"nick_name"`     //昵称
	Avatar         string `redis:"avatar"`        //头像地址
	Mobile         string `redis:"mobile"`        //联系手机号
	Gender         int8   `redis:"gender"`        //性别
	Birthday       string `redis:"birthday"`      //生日
	Slogan         string `redis:"slogan"`        //个性签名
	Idcard         string `redis:"idcard"`        //身份证号码
	RegionCode     string `redis:"region_code"`   //用户的地址行政编码
	RegionAddr     string `redis:"region_addr"`   //用户的详细地址,不包含region_code
	IsThirdAccount int8   `redis:"third_account"` //是否第三方账号
	RegPlat        int8   `redis:"reg_plat"`      //注册平台
	RegIp          string `redis:"reg_ip"`        //注册IP
	InviteCode     string `redis:"invite_code"`   //自己的邀请码
	Vuid           string `redis:"vuid"`          //设备号
	InviteBy       string `redis:"invite_by"`     //注册邀请来源者的邀请码
	InsertTime     string `redis:"insert_time"`   //插入时间
	UpdateTime     string `redis:"update_time"`   //更新时间
}
//第三方登录redis存储数据
type ThirdAccountUserInfo struct {
	Mobile  string `redis:"mobile"`
	QkQq    string `redis:"qkqq"`
	WeChat  string `redis:"wechat"`
	QkWeChatWeb string `redis:"qkwechatweb"`
	QkWeChat string `redis:"qkwechat"`
}
/*
	UserService
*/
type UserService struct{}

//获取userid对应的redis Key
func (p *UserService) GetUserInfoKey(userid string) string {
	return fmt.Sprintf("u:%s", userid)
}

//获取userid的全部信息
func (p *UserService) GetAllUserInfo(userid string) (*UserInfo, error) {
	if "" == userid {
		return nil, errors.New("userid is empty")
	}

	rkey := p.GetUserInfoKey(userid)
	conn := models.GetPassportModel().Get()
	defer conn.Close()
	var userinfo UserInfo
	if reply, err := redis.Values(conn.Do("hgetall", rkey)); err == nil {
		if len(reply) == 0 {
			return nil, nil
		}

		if err := redis.ScanStruct(reply, &userinfo); err == nil {
			return &userinfo, nil
		} else {
			return nil, err
		}
	} else if redis.ErrNil == err {
		return nil, nil
	} else {
		return nil, err
	}
}

//设置全部用户信息
func (p *UserService) setAllUserInfo(userinfo *UserInfo) error {
	key := p.GetUserInfoKey(userinfo.UserId)
	conn := models.GetPassportModel().Get()
	defer conn.Close()
	_, err := conn.Do("hmset", redis.Args{}.Add(key).AddFlat(userinfo)...)
	return err
}

//删除用户信息
func (p *UserService) deleteUserInfo(userid string) error {
	key := p.GetUserInfoKey(userid)
	conn := models.GetPassportModel().Get()
	defer conn.Close()
	_, err := conn.Do("del", key)
	return err
}

/*
	设置更新用户信息字段
*/
func (p *UserService) setAnyUserInfo(userid string, v ...interface{}) error {
	key := p.GetUserInfoKey(userid)
	conn := models.GetPassportModel().Get()
	defer conn.Close()
	_, err := conn.Do("hmset", redis.Args{}.Add(key).AddFlat(v)...)
	return err
}

func (p *UserService) setAnyUserInfoByMap(userid string, v map[string]interface{}) error {
	key := p.GetUserInfoKey(userid)
	conn := models.GetPassportModel().Get()
	defer conn.Close()
	_, err := conn.Do("hmset", redis.Args{}.Add(key).AddFlat(v)...)
	return err
}

/*
	获取用户信息字段值
*/
func (p *UserService) GetAnyUserInfo(userid string, keys ...interface{}) ([]interface{}, error) {
	key := p.GetUserInfoKey(userid)
	conn := models.GetPassportModel().Get()
	defer conn.Close()
	if reply, err := redis.Values(conn.Do("hmget", redis.Args{}.Add(key).AddFlat(keys)...)); err == nil {
		return reply, nil
	} else if redis.ErrNil == err {
		return nil, nil
	} else {
		return nil, err
	}
}

/*
	生成新的唯一userid
*/
func (p *UserService) GenerateNewUserid() (string, bool) {
	userid := utility.GenerateUUIDToken()
	return userid, true
}

/*
	将data中包含的字段更新到uid中
*/
func (p *UserService) UpdateUserProfileInfo(uid string, data map[string]interface{}) (uint, string) {
	ui, uiErr := p.GetAllUserInfo(uid)
	if uiErr != nil {
		log.Errorf("GetAllUserInfo failed for uid: %s, msg: %s", uid, uiErr.Error())
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR)
	}

	if ui == nil {
		log.Errorf("GetAllUserInfo get empty for uid: %s", uid)
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR)
	}

	changeCnt := 0
	uinfochanger := NewUserInfoChanger(uid)
	jq := jsonq.NewQuery(data)
	if val, err := jq.String("nick_name"); err == nil {
		if val == "" {
			log.Warnf("update user profile for userid: %s, nick_name is empty", uid)
			return errorcode.EC_USERINFO_SET_NICKNAME_EMPTY, "nickname is empty"
		}
		if len(val) > 32 {
			log.Warnf("update user profile for userid: %s, nick_name is too long, length: %d", uid, len(val))
			return errorcode.EC_USERINFO_SET_NICKNAME_TOO_LONG, "nickname length is too long"
		}

		if ui.NickName != val {
			uinfochanger.SetNickName(val)
			changeCnt += 1
		}
	}

	if val, err := jq.Int("gender"); err == nil {
		if val > 0 && val < 3 {
			if ui.Gender != int8(val) {
				uinfochanger.SetGender(int8(val))
				changeCnt += 1
			}
		} else {
			log.Warnf("update user profile for userid: %s, gender is unsupport, gender: %d", uid, val)
			return errorcode.EC_USERINFO_SET_GENDER_UNSUPPORT, "gender is invalid"
		}
	}

	if val, err := jq.String("slogan"); err == nil {
		if val == "" {
			log.Warnf("update user profile for userid: %s, slogan is empty", uid)
			return errorcode.EC_USERINFO_SET_SLOGAN_EMPTY, "slogan is empty"
		}
		if len(val) > 64 {
			log.Warnf("update user profile for userid: %s, slogan is too long, length: %d", uid, len(val))
			return errorcode.EC_USERINFO_SET_SLOGAN_TOO_LONG, "slogan length is too long"
		}
		if ui.Slogan != val {
			uinfochanger.SetSlogan(val)
			changeCnt += 1
		}
	}

	if val, err := jq.String("birthday"); err == nil {
		if len(val) != 10 { //YYYY-mm-dd
			log.Warnf("update user profile for userid: %s, birthday is incorrect, birthday: %s", uid, val)
			return errorcode.EC_USERINFO_SET_BIRTHDAY_INCORRECT, "birthday is incorrect"
		}
		if ui.Birthday != val {
			uinfochanger.SetBirthday(val)
			changeCnt += 1
		}
	}

	if val, err := jq.String("avatar"); err == nil {
		if val == "" {
			log.Warnf("update user profile for userid: %s, avatar is empty", uid)
			return errorcode.EC_USERINFO_SET_AVATAR_EMPTY, "avatar is empty"
		}
		if len(val) > 255 {
			log.Warnf("update user profile for userid: %s, avatar is too long, length: %d", uid, len(val))
			return errorcode.EC_USERINFO_SET_AVATAR_TOO_LONG, "avatar length is too long"
		}

		if strings.HasPrefix(val, models.GetAvatarURLPrefix()) {
			log.Warnf("update user profile for userid: %s, avatar is self, only third-party is acceptable", uid)
			return errorcode.EC_USERINFO_SET_AVATAR_NOT_SELFURL, "avatar is self, only third-party is acceptable"
		}

		if ui.Avatar != val {
			uinfochanger.SetAvatar(val)
			changeCnt += 1
		}
	}

	if val, err := jq.String("region_code"); err == nil {
		if ui.RegionCode != val {
			uinfochanger.SetRegionCode(val)
			changeCnt += 1
		}
	}

	if val, err := jq.String("region_addr"); err == nil {
		if ui.RegionAddr != val {
			uinfochanger.SetRegionAddr(val)
			changeCnt += 1
		}
	}

	if changeCnt > 0 {
		if err := uinfochanger.Save(); err != nil {
			log.Errorf("update user profile SetAllUserInfo error: %s", err.Error())
			return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR)
		}
	} else {
		log.Warnf("update user profile nothing is changed. uid: %s", uid)
	}
	return errorcode.EC_GL_SUCCESS, errorcode.Msg(errorcode.EC_GL_SUCCESS)
}

/*
	UserService处理对象
*/
func GetUserService() *UserService {
	return userservice
}

func init() {
	userservice = &UserService{}
}
